#include "rulebaseption2b.h"
#include <assert.h>

RuleBaseption2B::RuleBaseption2B()
{}

RuleBaseption2B::RuleBaseption2B(const RuleBaseption2B& other)
{
	vector<LongInstance2B>::const_iterator i;
	for (i = other.rules.begin(); i!= other.rules.end(); ++i)
		this->rules.push_back(*i);
}

RuleBaseption2B::RuleBaseption2B(const RuleBase2B& rb)
{
	bool* flag = new bool[rb.getInstanceNum()]; //flag[i] tells if the rule is rb is already used for the rule in this object or not.
	for (int i = 0; i < rb.getInstanceNum(); ++i)
		flag[i] = true;

	int conflicting = 0;
	for (int i = 0; i < rb.getInstanceNum(); ++i)
	{
		if (flag[i] == true) //false means the rule is not selected yet
		{
			flag[i] = false;
			LongInstance2B tempRule;
			conflicting = rb.indexOfConflicting(rb.getInstance(i));
			if (conflicting != -1) // if the conflicting rule exists
			{
				assert (flag[conflicting] == true && "How come the rule is not selected but its conflicting one is??");
				flag[conflicting] = false;
				int main, exception;
				if (rb.getInstance(i).getLabel() == BLACK)
				{
					main = i;
					exception = conflicting;
				}
				else
				{
					assert (rb.getInstance(conflicting).getLabel() == BLACK && "If the conflicting label is not black, this one should be");
					main = conflicting;
					exception = i;
				}
				tempRule = rb.getInstance(main);
				tempRule.clearCoordinates();
				for (int cooIndex = 0; cooIndex < rb.getInstance(exception).getCooNum(); ++cooIndex)
					tempRule.addCoordinate(rb.getInstance(exception).getCoordinate(cooIndex));
				this->rules.push_back(tempRule);
			}
			else // there is no conflicting rule
			{
				if (rb.getInstance(i).getLabel() == BLACK)
				{
					tempRule = rb.getInstance(i);
					tempRule.clearCoordinates();
					this->rules.push_back(tempRule);
				}
			}
		}
	}//end for
	delete[] flag;
}

RuleBaseption2B& RuleBaseption2B::operator= (const RuleBaseption2B& other)
{
	if (&other == this)
		return *this;
	vector<LongInstance2B>::const_iterator i;
	for (i = other.rules.begin(); i!= other.rules.end(); ++i)
		this->rules.push_back(*i);
	return *this;
}

bool RuleBaseption2B::cooIsException (const LongInstance2B& rule, const Coordinate& coo) const
{
	for (int cCounter = 0; cCounter < rule.getCooNum(); ++cCounter)
	{
		if (coo.isEqual(rule.getCoordinate(cCounter)))
			return true;
	}
	return false;
}

void RuleBaseption2B::advanceEIM (EightLayerIM& eim) const
{
	int nextLayerImage = eim.getValidImages();
	//replaced by the following line-- assert (this->rules.size() > 0 && this->rules[0].getFeatureSize() == nextLayerImage*this->rules[0].getNeighborhoodSize());
	assert (this->rules.size() > 0 && this->rules[0].neighborhoodNum() == nextLayerImage);
	assert (nextLayerImage > 0 && "EighLayerIM has no valid image.");
	assert (nextLayerImage < 8 && "No room for the next image, eim already full.");
	
	
	for (int row = 0; row < MROWS; ++row)
		for (int col = 0; col < MCOLS; ++col)
		{
			vector<Neighborhood2> nbs;
			Neighborhood2 nb;
			ImageMatrix thisIM;
			for (int n = 0; n < eim.getValidImages(); ++n)
			{
				//nb = new Neighborhood2;
				thisIM = eim.getImage(n);
				nb.updateFromImageMatrix(thisIM, row, col);
				nbs.push_back(nb);
			}
			bool aRuleApplies = false;
			for (int r = 0; r < (int) this->rules.size(); ++r)
			{
				if (rules[r].hasSameFeature(nbs) && !cooIsException(rules[r], Coordinate(row,col)))
					eim.setPixel(nextLayerImage,row,col,black);
				aRuleApplies = true;
			}

			if (!aRuleApplies)
				eim.setPixel(nextLayerImage,row,col,white);
		}
}

int RuleBaseption2B::getFeatureSize() const
{
	if (rules.size() == 0)
		return 0;
	return this->rules[0].getFeatureSize();
}

int RuleBaseption2B::getNetInfoSizeInBits(void) const
{
	if (rules.size() == 0)
		return 0; 
	int result = 0;
	for (int r = 0; r < (int)rules.size(); r++)
		result += rules[r].getNetInfoSizeInBits();
	return result;
}

double RuleBaseption2B::getAverageExceptionsPerRule(void) const
{
	int totalExceptions = 0;
	for (vector<LongInstance2B>::const_iterator it = rules.begin(); it != rules.end(); ++it)
		totalExceptions += (int) it->getCooNum();
	return ((double) totalExceptions) / ((double) rules.size());
}

int RuleBaseption2B::getRulesNum () const
{
	return (int)(rules.size());
}